/********************************************************************************
MIT License

Copyright(c) 3dRudder 2017

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
********************************************************************************/

#include "stdafx.h"
#include "3dRudderUnleashedVRConfig.h"
#include "3dRudderUnleashedVRConfigDlg.h"
#include "afxdialogex.h"
#include "DlgCurve.h"
#include <string>
#include "openvr.h"
#include "ProcessManagement.h"
#include "Registry.h"
#include "..\Common\MathTools.h"
#include "WaitDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


CString GetVersionProduct()
{
	TCHAR moduleName[MAX_PATH + 1];
	(void)GetModuleFileName(AfxGetInstanceHandle(), moduleName, MAX_PATH);
	DWORD dummyZero;
	DWORD versionSize = GetFileVersionInfoSize(moduleName, &dummyZero);
	if (versionSize == 0)
	{
		return CString(_T(""));
	}
	void* pVersion = malloc(versionSize);
	if (pVersion == NULL)
	{
		return CString(_T(""));
	}
	if (!GetFileVersionInfo(moduleName, NULL, versionSize, pVersion))
	{
		free(pVersion);
		return CString(_T(""));
	}

	UINT length;
	VS_FIXEDFILEINFO* pFixInfo;
	if (!VerQueryValue(pVersion, TEXT("\\"), (LPVOID*)&pFixInfo, &length))
	{
		free(pVersion);
		return CString(_T(""));
	}

	CString strProductVersion;
	strProductVersion.Format(_T("%u.%u.%u.%u"),
		HIWORD(pFixInfo->dwProductVersionMS),
		LOWORD(pFixInfo->dwProductVersionMS),
		HIWORD(pFixInfo->dwProductVersionLS),
		LOWORD(pFixInfo->dwProductVersionLS));

	free(pVersion);

	return strProductVersion;
}



// CAboutDlg dialog used for App About

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// Dialog Data
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	virtual BOOL OnInitDialog();

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
public:
	CString m_sVersion;
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
, m_sVersion(_T(""))
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Text(pDX, IDC_ST_VERSION, m_sVersion);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()

BOOL CAboutDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	m_sVersion.Format(_T("3dRudder Unleashed VR Configuration  v%s"), GetVersionProduct());
	UpdateData(FALSE);

	return TRUE;
}


// C3dRudderUnleashedVRConfig dialog

CSISharedMessageHandle g_SharedMessageHandleIn(_T("3dR_SI_MESS_IN"));
CSISharedMessageHandle g_SharedMessageHandleOut(_T("3dR_SI_MESS_OUT"));


C3dRudderUnleashedVRConfig::C3dRudderUnleashedVRConfig(CWnd* pParent /*=NULL*/)
	: CDialogEx(IDD_3DRUDDER_UNLEASHED_VR_DIALOG, pParent)
	, m_bNonSymPitch(TRUE)
	, m_bActivateCtrls(FALSE)
	, m_bActivateVRLocomotion(FALSE)
	, m_sSpeedAxisX(_T("1.0"))
	, m_sSpeedAxisY(_T("1.0"))
	, m_sSpeedAxisZ(_T("1.0"))
	, m_sSpeedRotateZ(_T("1.0"))
	, m_sHeightOffset(_T("0"))
	, m_bCalibrateInUse(FALSE)
	, m_bSmoothMode(FALSE)
	, m_sSmoothnessAx(_T(""))
	, m_sSmoothnessAy(_T(""))
	, m_sSmoothnessAz(_T(""))
	, m_sSmoothnessRz(_T(""))
	, m_sConfigLoaded(_T("No Config Loaded"))
{
	m_bActivated = FALSE;
	m_bDebug = TRUE;
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void C3dRudderUnleashedVRConfig::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Check(pDX, IDC_CK_NON_SYM_PITCH, m_bNonSymPitch);
	DDX_Check(pDX, IDC_CK_ACTIVATE_CTRLS, m_bActivateCtrls);
	DDX_Check(pDX, IDC_CK_ACTIVATE_VRLOCOMOTION, m_bActivateVRLocomotion);
	DDX_Text(pDX, IDC_ED_SPEED_AX, m_sSpeedAxisX);
	DDX_Text(pDX, IDC_ED_SPEED_AY, m_sSpeedAxisY);
	DDX_Text(pDX, IDC_ED_SPEED_AZ, m_sSpeedAxisZ);
	DDX_Text(pDX, IDC_ED_SPEED_RZ, m_sSpeedRotateZ);
	DDX_Control(pDX, IDC_ED_SPEED_AX, m_EdSpeedAx);
	DDX_Control(pDX, IDC_ED_SPEED_AY, m_EdSpeedAy);
	DDX_Control(pDX, IDC_ED_SPEED_AZ, m_EdSpeedAz);
	DDX_Control(pDX, IDC_ED_SPEED_RZ, m_EdSpeedRz);
	DDX_Text(pDX, IDC_ED_HEIGHT_OFFSET, m_sHeightOffset);
	DDX_Control(pDX, IDC_ED_HEIGHT_OFFSET, m_EdHeightOffset);
	DDX_Control(pDX, IDC_BT_RESET, m_BtReset);
	DDX_Control(pDX, IDC_CB_DRIVER, m_CbDriver);
	DDX_Control(pDX, IDC_BT_ACTIVATE, m_BtActivate);
	DDX_Control(pDX, IDC_BT_CALIBRATION, m_BtCalibration);
	DDX_Control(pDX, IDC_ST_VAL1, m_StVal1);
	DDX_Control(pDX, IDC_ST_VAL2, m_StVal2);
	DDX_Control(pDX, IDC_ST_VAL3, m_StVal3);
	DDX_Control(pDX, IDC_ST_VAL4, m_StVal4);
	DDX_Control(pDX, IDC_ST_VAL5, m_StVal5);
	DDX_Control(pDX, IDC_ST_VAL6, m_StVal6);
	DDX_Control(pDX, IDC_ST_VAL7, m_StValX);
	DDX_Control(pDX, IDC_ST_VAL8, m_StValY);
	DDX_Control(pDX, IDC_ST_VAL9, m_StValZ);
	DDX_Check(pDX, IDC_CK_CALIBRATE_INUSE, m_bCalibrateInUse);
	DDX_Control(pDX, IDC_CK_CALIBRATE_INUSE, m_BtCalibrateInUse);
	DDX_Control(pDX, IDC_CK_ACTIVATE_VRLOCOMOTION, m_BtActivateVRLocomotion);
	DDX_Control(pDX, IDC_CK_ACTIVATE_CTRLS, m_BtActivateControllers);
	DDX_Control(pDX, IDC_CB_L_H, m_CbLeftH);
	DDX_Control(pDX, IDC_CB_L_V, m_CbLeftV);
	DDX_Control(pDX, IDC_CB_L_T, m_CbLeftT);
	DDX_Control(pDX, IDC_CB_R_H, m_CbRightH);
	DDX_Control(pDX, IDC_CB_R_V, m_CbRightV);
	DDX_Control(pDX, IDC_CB_R_T, m_CbRightT);
	DDX_Control(pDX, IDC_ST_SPEED_AX, m_StSpeedAx);
	DDX_Control(pDX, IDC_ST_SPEED_AY, m_StSpeedAy);
	DDX_Control(pDX, IDC_ST_SPEED_AZ, m_StSpeedAz);
	DDX_Control(pDX, IDC_ST_SPEED_RZ, m_StSpeedRz);
	DDX_Control(pDX, IDC_ST_L_CTRL, m_StLCtrl);
	DDX_Control(pDX, IDC_ST_L_H, m_StLeftH);
	DDX_Control(pDX, IDC_ST_L_V, m_StLeftV);
	DDX_Control(pDX, IDC_ST_L_T, m_StLeftT);
	DDX_Control(pDX, IDC_ST_R_CTRL, m_StRCtrl);
	DDX_Control(pDX, IDC_ST_R_H, m_StRightH);
	DDX_Control(pDX, IDC_ST_R_V, m_StRightV);
	DDX_Control(pDX, IDC_ST_R_T, m_StRightT);
	DDX_Control(pDX, IDC_BT_DEBUG, m_BtDebug);
	DDX_Control(pDX, IDC_ST_DEBUG, m_StDebug);
	DDX_Control(pDX, IDC_ST_3D, m_St3D);
	DDX_Control(pDX, IDC_SL_SPEED_AX, m_SlSpeedAx);
	DDX_Control(pDX, IDC_SL_SPEED_AY, m_SlSpeedAy);
	DDX_Control(pDX, IDC_SL_SPEED_AZ, m_SlSpeedAz);
	DDX_Control(pDX, IDC_SL_SPEED_RZ, m_SlSpeedRz);
	DDX_Control(pDX, IDC_SL_HOFFSET, m_SlHOffset);
	DDX_Check(pDX, IDC_CK_SMOOTH_MODE, m_bSmoothMode);
	DDX_Control(pDX, IDC_CK_SMOOTH_MODE, m_BtSmoothMode);
	DDX_Control(pDX, IDC_SL_SMOOTH_AX, m_SlSmoothnessAx);
	DDX_Control(pDX, IDC_SL_SMOOTH_AY, m_SlSmoothnessAy);
	DDX_Control(pDX, IDC_SL_SMOOTH_AZ, m_SlSmoothnessAz);
	DDX_Control(pDX, IDC_SL_SMOOTH_RZ, m_SlSmoothnessRz);
	DDX_Text(pDX, IDC_ED_SMOOTH_AX, m_sSmoothnessAx);
	DDX_Text(pDX, IDC_ED_SMOOTH_AY, m_sSmoothnessAy);
	DDX_Text(pDX, IDC_ED_SMOOTH_AZ, m_sSmoothnessAz);
	DDX_Text(pDX, IDC_ED_SMOOTH_RZ, m_sSmoothnessRz);
	DDX_Control(pDX, IDC_ED_SMOOTH_AX, m_EdSmoothAx);
	DDX_Control(pDX, IDC_ED_SMOOTH_AY, m_EdSmoothAy);
	DDX_Control(pDX, IDC_ED_SMOOTH_AZ, m_EdSmoothAz);
	DDX_Control(pDX, IDC_ED_SMOOTH_RZ, m_EdSmoothRz);
	DDX_Control(pDX, IDC_ST_SMOOTH_AX, m_StSmotthAx);
	DDX_Control(pDX, IDC_ST_SMOOTH_AY, m_StSmotthAy);
	DDX_Control(pDX, IDC_ST_SMOOTH_AZ, m_StSmotthAz);
	DDX_Control(pDX, IDC_ST_SMOOTH_RZ, m_StSmotthRz);
	DDX_Text(pDX, IDC_ST_CONFIG_LOADED, m_sConfigLoaded);
}

BEGIN_MESSAGE_MAP(C3dRudderUnleashedVRConfig, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDCANCEL, &C3dRudderUnleashedVRConfig::OnBnClickedCancel)
	ON_BN_CLICKED(IDOK, &C3dRudderUnleashedVRConfig::OnBnClickedOk)
	ON_BN_CLICKED(IDC_BT_CURVE_X, &C3dRudderUnleashedVRConfig::OnBnClickedBtCurveX)
	ON_BN_CLICKED(IDC_BT_CURVE_Y, &C3dRudderUnleashedVRConfig::OnBnClickedBtCurveY)
	ON_BN_CLICKED(IDC_BT_CURVE_Z, &C3dRudderUnleashedVRConfig::OnBnClickedBtCurveZ)
	ON_BN_CLICKED(IDC_BT_CURVE_RZ, &C3dRudderUnleashedVRConfig::OnBnClickedBtCurveRz)
	ON_WM_TIMER()
	ON_BN_CLICKED(IDC_BT_LOAD, &C3dRudderUnleashedVRConfig::OnBnClickedBtLoad)
	ON_BN_CLICKED(IDC_BT_SAVE, &C3dRudderUnleashedVRConfig::OnBnClickedBtSave)
	ON_BN_CLICKED(IDC_CK_ACTIVATE_CTRLS, &C3dRudderUnleashedVRConfig::OnBnClickedCkActivateCtrls)
	ON_BN_CLICKED(IDC_CK_ACTIVATE_VRLOCOMOTION, &C3dRudderUnleashedVRConfig::OnBnClickedCkActivateVRLocomotion)
	ON_BN_CLICKED(IDC_BT_ACTIVATE, &C3dRudderUnleashedVRConfig::OnBnClickedBtActivate)
	ON_BN_CLICKED(IDC_BT_RESET, &C3dRudderUnleashedVRConfig::OnBnClickedBtReset)
	ON_WM_DESTROY()
	ON_BN_CLICKED(IDC_BT_CALIBRATION, &C3dRudderUnleashedVRConfig::OnBnClickedBtCalibration)
	ON_BN_CLICKED(IDC_BT_DEBUG, &C3dRudderUnleashedVRConfig::OnBnClickedBtDebug)
	ON_EN_CHANGE(IDC_ED_SPEED_AX, &C3dRudderUnleashedVRConfig::OnEnChangeEdSpeedAx)
	ON_EN_CHANGE(IDC_ED_SPEED_AY, &C3dRudderUnleashedVRConfig::OnEnChangeEdSpeedAy)
	ON_EN_CHANGE(IDC_ED_SPEED_AZ, &C3dRudderUnleashedVRConfig::OnEnChangeEdSpeedAz)
	ON_EN_CHANGE(IDC_ED_SPEED_RZ, &C3dRudderUnleashedVRConfig::OnEnChangeEdSpeedRz)
	ON_EN_CHANGE(IDC_ED_HEIGHT_OFFSET, &C3dRudderUnleashedVRConfig::OnEnChangeEdHeightOffset)
	ON_WM_HSCROLL()
	ON_BN_CLICKED(IDC_CK_SMOOTH_MODE, &C3dRudderUnleashedVRConfig::OnBnClickedCkSmoothMode)
	ON_EN_CHANGE(IDC_ED_SMOOTH_AX, &C3dRudderUnleashedVRConfig::OnEnChangeEdSmoothAx)
	ON_EN_CHANGE(IDC_ED_SMOOTH_AY, &C3dRudderUnleashedVRConfig::OnEnChangeEdSmoothAy)
	ON_EN_CHANGE(IDC_ED_SMOOTH_AZ, &C3dRudderUnleashedVRConfig::OnEnChangeEdSmoothAz)
	ON_EN_CHANGE(IDC_ED_SMOOTH_RZ, &C3dRudderUnleashedVRConfig::OnEnChangeEdSmoothRz)
	ON_WM_HSCROLL()
END_MESSAGE_MAP()




// C3dRudderUnleashedVRConfig message handlers

BOOL C3dRudderUnleashedVRConfig::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	CRegistry reg;

	if (reg.OpenKey(CRegistry::currentUser, _T("SOFTWARE\\Valve\\Steam")))
	{
		if (reg.GetValue(_T("SteamPath"), m_sSteamPath))
		{
			m_sSteamPath.Replace(_T("/"), _T("\\"));
			CString sPath = m_sSteamPath + _T("\\steamapps\\common\\SteamVR\\drivers\\*.*");

			CFileFind finder;
			BOOL bWorking = finder.FindFile(sPath);
			while (bWorking)
			{
				bWorking = finder.FindNextFile();
				if (finder.IsDirectory()&& finder.GetFileName() != _T(".")&& finder.GetFileName() != _T(".."))
				{
					CFileFind finder2;
					CString sPath2 = finder.GetFilePath() + _T("\\*.*");
					BOOL bWorking2 = finder2.FindFile(sPath2);
					while (bWorking2)
					{
						bWorking2 = finder2.FindNextFile();
						if (finder2.IsDirectory() && finder2.GetFileName() == _T("bin"))
						{
							m_CbDriver.AddString(finder.GetFileName());
						}
					}
				}
			}
		}
		else
		{
			AfxMessageBox(_T("Can't find steam path"));
		}
	}
	else
	{
		AfxMessageBox(_T("Steam is not installed"));
	}


	m_StVal1.SetWindowText(_T(""));
	m_StVal2.SetWindowText(_T(""));
	m_StVal3.SetWindowText(_T(""));
	m_StVal4.SetWindowText(_T(""));
	m_StVal5.SetWindowText(_T(""));
	m_StVal6.SetWindowText(_T(""));
	m_StValX.SetWindowText(_T(""));
	m_StValY.SetWindowText(_T(""));
	m_StValZ.SetWindowText(_T(""));


	CString sTitleText;
	sTitleText.Format(_T("3dRudder Unleashed VR Configuration  v%s"), GetVersionProduct());
	SetWindowText(sTitleText);


	ID2D1Factory* m_pDirect2dFactory;
	D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pDirect2dFactory);

	FLOAT dpiX, dpiY;
	m_pDirect2dFactory->GetDesktopDpi(&dpiX, &dpiY);

	m_fDPIx = (float)round(dpiX / 100.0f);
	m_fDPIy = (float)round(dpiY / 100.0f);
	OnBnClickedBtDebug();

	m_CbDriver.SetCurSel(m_CbDriver.FindString(0,_T("lighthouse")));


	m_pSdk = ns3dRudder::GetSDK();
	m_pSdk->Init();
	

	CString sAxisText[] = { _T("Default"),_T("Left/Right"),_T("Backward/Forward"),_T("Up/Down"),_T("Rotation Left/Right") };
	CString sHalfAxisText[] = { _T("Default"),_T("Left"),_T("Right"),_T("Backward"),_T("Forward"),_T("Up"),_T("Down"),_T("Rotation Left"),_T("Rotation Right") };
	// trackpads X Y
	for (int i = 0; i < 5; ++i)
	{
		m_CbLeftH.AddString(sAxisText[i]);
		m_CbLeftV.AddString(sAxisText[i]);
		m_CbRightH.AddString(sAxisText[i]);
		m_CbRightV.AddString(sAxisText[i]);		
	}
	// triggers X Y=0
	for (int i = 0; i < 9; ++i)
	{
		m_CbLeftT.AddString(sHalfAxisText[i]);
		m_CbRightT.AddString(sHalfAxisText[i]);
	}

	m_CbLeftH.SetCurSel(0);
	m_CbLeftV.SetCurSel(0);
	m_CbLeftT.SetCurSel(0);
	m_CbRightH.SetCurSel(0);
	m_CbRightV.SetCurSel(0);
	m_CbRightT.SetCurSel(0);

	m_MaxSpeedAx = 10;
	m_MaxSpeedAy = 10;
	m_MaxSpeedAz = 10;
	m_MaxSpeedRz = 10;
	m_nMaxHOffset = 10;
	m_SlSpeedAx.SetRange(-m_MaxSpeedAx * 100, m_MaxSpeedAx * 100);
	m_SlSpeedAx.SetTicFreq(m_MaxSpeedAx * 100/10);
	m_SlSpeedAy.SetRange(-m_MaxSpeedAy * 100, m_MaxSpeedAy * 100);
	m_SlSpeedAy.SetTicFreq(m_MaxSpeedAy * 100 / 10);
	m_SlSpeedAz.SetRange(-m_MaxSpeedAz * 100, m_MaxSpeedAz * 100);
	m_SlSpeedAz.SetTicFreq(m_MaxSpeedAz * 100 / 10);
	m_SlSpeedRz.SetRange(-m_MaxSpeedRz * 100, m_MaxSpeedRz * 100);
	m_SlSpeedRz.SetTicFreq(m_MaxSpeedRz * 100 / 10);
	m_SharedData.m_fSpeed[0] = (float)_wtof(m_sSpeedAxisX);
	m_SharedData.m_fSpeed[1] = (float)_wtof(m_sSpeedAxisY);
	m_SharedData.m_fSpeed[2] = (float)_wtof(m_sSpeedAxisZ);
	m_SharedData.m_fSpeed[3] = (float)_wtof(m_sSpeedRotateZ);
	m_SlSpeedAx.SetPos(int(m_SharedData.m_fSpeed[0] * 100));
	m_SlSpeedAy.SetPos(int(m_SharedData.m_fSpeed[0] * 100));
	m_SlSpeedAz.SetPos(int(m_SharedData.m_fSpeed[0] * 100));
	m_SlSpeedRz.SetPos(int(m_SharedData.m_fSpeed[0] * 100));

	m_SharedData.m_fHeightOffset = (float)_wtof(m_sHeightOffset);
	m_SlHOffset.SetRange(-m_nMaxHOffset * 100, m_nMaxHOffset * 100);
	m_SlHOffset.SetTicFreq(m_nMaxHOffset * 100 / 10);
	m_SlHOffset.SetPos(int(m_SharedData.m_fHeightOffset * 100));

	OnEnChangeEdSpeedAx();
	OnEnChangeEdSpeedAy();
	OnEnChangeEdSpeedAz();
	OnEnChangeEdSpeedRz();
	OnEnChangeEdHeightOffset();
	UpdateSliderValue();

	m_SlSmoothnessAx.SetRange(50, 1000);
	m_SlSmoothnessAx.SetTicFreq(200);
	m_SlSmoothnessAy.SetRange(50, 1000);
	m_SlSmoothnessAy.SetTicFreq(200);
	m_SlSmoothnessAz.SetRange(50, 1000);
	m_SlSmoothnessAz.SetTicFreq(200);
	m_SlSmoothnessRz.SetRange(50, 1000);
	m_SlSmoothnessRz.SetTicFreq(200);
	m_SlSmoothnessAx.SetPos(int(m_SharedData.m_fSmoothValue[0] * 1000));
	m_SlSmoothnessAy.SetPos(int(m_SharedData.m_fSmoothValue[1] * 1000));
	m_SlSmoothnessAz.SetPos(int(m_SharedData.m_fSmoothValue[2] * 1000));
	m_SlSmoothnessRz.SetPos(int(m_SharedData.m_fSmoothValue[3] * 1000));
	m_sSmoothnessAx.Format(_T("%.3f"), m_SharedData.m_fSmoothValue[0]);
	m_sSmoothnessAy.Format(_T("%.3f"), m_SharedData.m_fSmoothValue[1]);
	m_sSmoothnessAz.Format(_T("%.3f"), m_SharedData.m_fSmoothValue[2]);
	m_sSmoothnessRz.Format(_T("%.3f"), m_SharedData.m_fSmoothValue[3]);

	UpdateData(FALSE);


	m_SharedMemory.Open(_T("3dR_SI_DATA"), sizeof(CSISharedData));
	m_SharedMemoryDebug.Open(_T("3dR_SI_DATA_DEBUG"), sizeof(CSISharedDataDebug));

	SetTimer(0, 50, NULL);
	CheckActivate();
	ManageActivateUI();

	FILE *pFile = _wfopen(_T("DefaultConfig.txt"), _T("rt"));
	if (pFile)
	{
		fclose(pFile);

		Load(_T("DefaultConfig.txt"));
	}


	return TRUE;  // return TRUE  unless you set the focus to a control
}

void C3dRudderUnleashedVRConfig::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void C3dRudderUnleashedVRConfig::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);

	}
	else
	{
		CDialogEx::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR C3dRudderUnleashedVRConfig::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



void C3dRudderUnleashedVRConfig::OnBnClickedCancel()
{
	// TODO: Add your control notification handler code here
	CDialogEx::OnCancel();
}


void C3dRudderUnleashedVRConfig::OnBnClickedOk()
{

}


void C3dRudderUnleashedVRConfig::OnBnClickedBtCurveX()
{
	CDlgCurve dlg(&m_SharedData.m_Curve[ns3dRudder::CurveXAxis],&m_Axis.m_aX);
	dlg.DoModal();

}


void C3dRudderUnleashedVRConfig::OnBnClickedBtCurveY()
{
	CDlgCurve dlg(&m_SharedData.m_Curve[ns3dRudder::CurveYAxis], &m_Axis.m_aY);
	dlg.DoModal();

}


void C3dRudderUnleashedVRConfig::OnBnClickedBtCurveZ()
{
	CDlgCurve dlg(&m_SharedData.m_Curve[ns3dRudder::CurveZAxis], &m_Axis.m_aZ);
	dlg.DoModal();

}


void C3dRudderUnleashedVRConfig::OnBnClickedBtCurveRz()
{
	CDlgCurve dlg(&m_SharedData.m_Curve[ns3dRudder::CurveZRotation], &m_Axis.m_rZ);
	dlg.DoModal();

}


void C3dRudderUnleashedVRConfig::OnTimer(UINT_PTR nIDEvent)
{
	UpdateData(TRUE);
	
	m_pSdk->GetAxis(0, ns3dRudder::NormalizedValue, &m_Axis);
	CSISharedDataDebug SharedDataDebug;
	m_SharedMemoryDebug.Read((uint8_t*)&SharedDataDebug, sizeof(CSISharedDataDebug));

	CString sText;
	sText.Format(_T("Position Initial : (%f,%f,%f)"), SharedDataDebug.m_PositionInitial.m_fx, SharedDataDebug.m_PositionInitial.m_fy, SharedDataDebug.m_PositionInitial.m_fz);
	m_StVal1.SetWindowText(sText);
	sText.Format(_T("Rotation Initial : (%f,%f,%f,%f)"), SharedDataDebug.m_RotationInitial.m_fx, SharedDataDebug.m_RotationInitial.m_fy, SharedDataDebug.m_RotationInitial.m_fz, SharedDataDebug.m_RotationInitial.m_fw);
	m_StVal2.SetWindowText(sText);
	sText.Format(_T("Translation/Angle : (%f,%f,%f,%f"), SharedDataDebug.m_TranslationXYZAngleW.m_fx, SharedDataDebug.m_TranslationXYZAngleW.m_fy, SharedDataDebug.m_TranslationXYZAngleW.m_fz, SharedDataDebug.m_TranslationXYZAngleW.m_fw);
	m_StVal3.SetWindowText(sText);
	sText.Format(_T("Smooth Speed: (%f,%f,%f,%f"), SharedDataDebug.m_SmoothSpeed.m_fx, SharedDataDebug.m_SmoothSpeed.m_fy, SharedDataDebug.m_SmoothSpeed.m_fz, SharedDataDebug.m_SmoothSpeed.m_fw);
	m_StVal4.SetWindowText(sText);
	if (SharedDataDebug.m_fDeltaTime > 0)
	{
		sText.Format(_T("Delta Time Runframe: (%f)  = FPS : (%f)"), SharedDataDebug.m_fDeltaTime, 1.0 / SharedDataDebug.m_fDeltaTime);
		m_StVal5.SetWindowText(sText);
	}

	m_SharedData.m_nAxis[0] = (CSISharedData::AxisValue)m_CbLeftH.GetCurSel();
	m_SharedData.m_nAxis[1] = (CSISharedData::AxisValue)m_CbLeftV.GetCurSel();	
	m_SharedData.m_nAxis[2] = (CSISharedData::AxisValue)m_CbRightH.GetCurSel();
	m_SharedData.m_nAxis[3] = (CSISharedData::AxisValue)m_CbRightV.GetCurSel();	
	m_SharedData.m_nHalfAxis[0] = (CSISharedData::HalfAxisValue)m_CbLeftT.GetCurSel();
	m_SharedData.m_nHalfAxis[1] = (CSISharedData::HalfAxisValue)m_CbRightT.GetCurSel();

	vr::IVRSystem *pOpenVR = vr::VRSystem();
	if (pOpenVR != nullptr)
	{
		/******DEBUG******/
		// for somebody asking for the default figure out the time from now to photons.
		float fSecondsSinceLastVsync;
		pOpenVR->GetTimeSinceLastVsync(&fSecondsSinceLastVsync, NULL);
		float fDisplayFrequency = vr::VRSystem()->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_DisplayFrequency_Float);
		float fFrameDuration = fDisplayFrequency > 0 ? 1.f / fDisplayFrequency : 0;
		float fVsyncToPhotons = vr::VRSystem()->GetFloatTrackedDeviceProperty(vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SecondsFromVsyncToPhotons_Float);

		float fPredictedSecondsFromNow = fFrameDuration - fSecondsSinceLastVsync + fVsyncToPhotons;
		vr::TrackedDevicePose_t hmdPose;
		vr::VRCompositor()->GetLastPoseForTrackedDeviceIndex(vr::k_unTrackedDeviceIndex_Hmd, nullptr, &hmdPose);
		Mat_33 HmdRotationMat;
		for (int i = 0; i < 3; ++i)
			for (int j = 0; j < 3; ++j)
				HmdRotationMat[i][j] = hmdPose.mDeviceToAbsoluteTracking.m[i][j];
		vr::HmdQuaternion_t HmdRotationQuat;
		MatToQuat(HmdRotationMat, HmdRotationQuat);
		sText.Format(_T("qR : (%f,%f,%f,%f)"), HmdRotationQuat.x, HmdRotationQuat.y, HmdRotationQuat.z, HmdRotationQuat.w);
		m_StVal6.SetWindowText(sText);
		sText.Format(_T("aX : (%f,%f,%f)"), HmdRotationMat[0][0], HmdRotationMat[1][0], HmdRotationMat[2][0]);
		m_StValX.SetWindowText(sText);
		sText.Format(_T("aY : (%f,%f,%f)"), HmdRotationMat[0][1], HmdRotationMat[1][1], HmdRotationMat[2][1]);
		m_StValY.SetWindowText(sText);
		sText.Format(_T("aZ : (%f,%f,%f)"), HmdRotationMat[0][2], HmdRotationMat[1][2], HmdRotationMat[2][2]);
		m_StValZ.SetWindowText(sText);

		// Controller Role		
		vr::VREvent_t pEvent;
		// TODO : test without for
		for (int i = 0; i < 64; i++)
		{
			if (!pOpenVR->PollNextEvent(&pEvent, sizeof(vr::VREvent_t)))
				break;

			// Get event for the role
			if (pEvent.eventType == vr::VREvent_TrackedDeviceRoleChanged ||	pEvent.eventType == vr::VREvent_TrackedDeviceActivated || pEvent.eventType == vr::VREvent_TrackedDeviceDeactivated)
				RefreshController();
		}
	}

	m_SharedData.m_bActivateCtrls = !!m_bActivateCtrls;
	m_SharedData.m_fHeightOffset = (float)_wtof(m_sHeightOffset);
	
	m_SharedData.m_bActivateVRLocomotion = !!m_bActivateVRLocomotion;
	m_SharedData.m_fSpeed[0] = (float)_wtof(m_sSpeedAxisX);
	m_SharedData.m_fSpeed[1] = (float)_wtof(m_sSpeedAxisY);
	m_SharedData.m_fSpeed[2] = (float)_wtof(m_sSpeedAxisZ);
	m_SharedData.m_fSpeed[3] = (float)_wtof(m_sSpeedRotateZ);

	m_SharedData.m_fSmoothValue[0] = (float)_wtof(m_sSmoothnessAx);
	m_SharedData.m_fSmoothValue[1] = (float)_wtof(m_sSmoothnessAy);
	m_SharedData.m_fSmoothValue[2] = (float)_wtof(m_sSmoothnessAz);
	m_SharedData.m_fSmoothValue[3] = (float)_wtof(m_sSmoothnessRz);


	m_SharedData.m_bNonSymPitch = !!m_bNonSymPitch;
	m_SharedData.m_bCalibrateOnInUse = !!m_bCalibrateInUse;
	m_SharedData.m_bSmoothMode = !!m_bSmoothMode;

	m_SharedMemory.Write((uint8_t*)&m_SharedData, sizeof(CSISharedData));


	CSI_Message *pMessage;

	while (pMessage = g_SharedMessageHandleOut.PopMessage())
	{
		switch (pMessage->m_nType)
		{
			case CSiMessageeType::Calibration:
			{
				SendMatrixHmd();
			}
			break;
			default:
			break;
		}

		delete pMessage;
	}


	CDialogEx::OnTimer(nIDEvent);
}


std::string ConvUnicodeString(CString sString)
{
	char *sStringChar = new char[sString.GetLength() + 1];
	size_t CharactersConverted = 0;
	wcstombs_s(&CharactersConverted, sStringChar, sString.GetLength() + 1, sString, _TRUNCATE);

	std::string sNewString(sStringChar);

	delete[] sStringChar;
	return sNewString;
}

void C3dRudderUnleashedVRConfig::SendMatrixHmd()
{
	if (vr::VRSystem() != nullptr)
	{
		// Send pose and orientation
		vr::TrackedDevicePose_t hmdPose;
		vr::VRCompositor()->GetLastPoseForTrackedDeviceIndex(vr::k_unTrackedDeviceIndex_Hmd, nullptr, &hmdPose);
		if (hmdPose.bPoseIsValid)
		{
			CSI_MessageCalibration msgCalib;
			memcpy(&msgCalib.m_matrix, &hmdPose.mDeviceToAbsoluteTracking.m, sizeof(CSISharedData::Matrix34));
			g_SharedMessageHandleIn.PushMessage(&msgCalib);
		}
	}
}

void C3dRudderUnleashedVRConfig::RefreshController()
{
	vr::IVRSystem *pOpenVR = vr::VRSystem();
	if (pOpenVR != nullptr)
	{
		// LEFT
		vr::TrackedDeviceIndex_t leftIndex = pOpenVR->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_LeftHand);
		if (leftIndex != vr::k_unTrackedDeviceIndexInvalid && m_SharedData.m_nPadIndex[0] != leftIndex)
			m_SharedData.m_nPadIndex[0] = leftIndex;
		// RIGHT
		vr::TrackedDeviceIndex_t rightIndex = pOpenVR->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand);
		if (rightIndex != vr::k_unTrackedDeviceIndexInvalid && m_SharedData.m_nPadIndex[1] != rightIndex)
			m_SharedData.m_nPadIndex[1] = rightIndex;
	}
}


bool C3dRudderUnleashedVRConfig::Load(wchar_t *pPath)
{
	bool bRet = false;
	if (m_SharedData.Load(pPath))
	{
		m_bActivateCtrls = m_SharedData.m_bActivateCtrls;
		m_CbLeftH.SetCurSel(m_SharedData.m_nAxis[0]);
		m_CbLeftV.SetCurSel(m_SharedData.m_nAxis[1]);
		m_CbRightH.SetCurSel(m_SharedData.m_nAxis[2]);
		m_CbRightV.SetCurSel(m_SharedData.m_nAxis[3]);
		m_CbLeftT.SetCurSel(m_SharedData.m_nHalfAxis[0]);
		m_CbRightT.SetCurSel(m_SharedData.m_nHalfAxis[1]);

		m_bActivateVRLocomotion = m_SharedData.m_bActivateVRLocomotion;
		m_sSpeedAxisX.Format(_T("%.2f"), m_SharedData.m_fSpeed[0]);
		m_sSpeedAxisY.Format(_T("%.2f"), m_SharedData.m_fSpeed[1]);
		m_sSpeedAxisZ.Format(_T("%.2f"), m_SharedData.m_fSpeed[2]);
		m_sSpeedRotateZ.Format(_T("%.2f"), m_SharedData.m_fSpeed[3]);

		m_bNonSymPitch = m_SharedData.m_bNonSymPitch;
		m_bCalibrateInUse = m_SharedData.m_bCalibrateOnInUse;
		m_bSmoothMode = m_SharedData.m_bSmoothMode;
		m_sHeightOffset.Format(_T("%.2f"), m_SharedData.m_fHeightOffset);

		TCHAR fname[_MAX_FNAME];
		_tsplitpath(pPath, NULL, NULL, fname,NULL);

		m_sConfigLoaded.Format(_T("Config : %s"), fname);

		UpdateData(FALSE);
		ManageActivateUI();

		OnEnChangeEdSpeedAx();
		OnEnChangeEdSpeedAy();
		OnEnChangeEdSpeedAz();
		OnEnChangeEdSpeedRz();
		OnEnChangeEdHeightOffset();
		//UpdateSliderValue();
		bRet = true;
	}
	return bRet;
}

void C3dRudderUnleashedVRConfig::OnBnClickedBtLoad()
{
	TCHAR szFilters[] = _T("txt Files (*.txt)|*.txt|All Files (*.*)|*.*||");
	CFileDialog fileDlg(TRUE, _T("txt"), _T("*.txt"), OFN_FILEMUSTEXIST, szFilters);
	if (fileDlg.DoModal() == IDOK)
	{
		CString pathName = fileDlg.GetPathName();

		if (Load(pathName.GetBuffer()))
			AfxMessageBox(_T("Config Loader ! Enjoy ! "), MB_OK | MB_ICONINFORMATION);
		else 
			AfxMessageBox(_T("Config Loader Error ... "), MB_OK | MB_ICONERROR);
	}
}


void C3dRudderUnleashedVRConfig::OnBnClickedBtSave()
{
	UpdateData(TRUE);
	TCHAR szFilters[] = _T("txt Files (*.txt)|*.txt|All Files (*.*)|*.*||");
	CFileDialog fileDlg(FALSE, _T("txt"), _T("*.txt"), OFN_FILEMUSTEXIST, szFilters);
	if (fileDlg.DoModal() == IDOK)
	{
		CString pathName = fileDlg.GetPathName();
		if(m_SharedData.Save(pathName.GetBuffer()))
			AfxMessageBox(_T("Config Saved ! Enjoy ! "), MB_OK | MB_ICONINFORMATION);
		else
			AfxMessageBox(_T("Config Saved Error ... "), MB_OK | MB_ICONERROR);

	}
}


void C3dRudderUnleashedVRConfig::ManageActivateUI()
{
	m_BtActivateVRLocomotion.EnableWindow(m_bActivated);
	m_BtActivateControllers.EnableWindow(m_bActivated);
	m_BtCalibration.EnableWindow(m_bActivated);
	OnBnClickedCkActivateCtrls();
	OnBnClickedCkActivateVRLocomotion();
}

void C3dRudderUnleashedVRConfig::OnBnClickedCkActivateCtrls()
{
	UpdateData(TRUE);

	m_CbLeftH.EnableWindow(m_bActivateCtrls&&m_bActivated);
	m_CbLeftV.EnableWindow(m_bActivateCtrls&&m_bActivated);
	m_CbLeftT.EnableWindow(m_bActivateCtrls&&m_bActivated);
	m_CbRightH.EnableWindow(m_bActivateCtrls&&m_bActivated);
	m_CbRightV.EnableWindow(m_bActivateCtrls&&m_bActivated);
	m_CbRightT.EnableWindow(m_bActivateCtrls&&m_bActivated);

	m_StLCtrl.EnableWindow(m_bActivateCtrls&&m_bActivated);
	m_StLeftH.EnableWindow(m_bActivateCtrls&&m_bActivated);
	m_StLeftV.EnableWindow(m_bActivateCtrls&&m_bActivated);
	m_StLeftT.EnableWindow(m_bActivateCtrls&&m_bActivated);

	m_StRCtrl.EnableWindow(m_bActivateCtrls&&m_bActivated);
	m_StRightH.EnableWindow(m_bActivateCtrls&&m_bActivated);
	m_StRightV.EnableWindow(m_bActivateCtrls&&m_bActivated);
	m_StRightT.EnableWindow(m_bActivateCtrls&&m_bActivated);

	RefreshController();

	m_SharedData.m_bActivateCtrls = !!m_bActivateCtrls;
	m_SharedMemory.Write((uint8_t*)&m_SharedData, sizeof(CSISharedData));
}


void C3dRudderUnleashedVRConfig::OnBnClickedBtReset()
{
	CSI_MessageReset msg;
	msg.m_bReset = true;
	g_SharedMessageHandleIn.PushMessage(&msg);
}


void C3dRudderUnleashedVRConfig::OnBnClickedCkActivateVRLocomotion()
{
	UpdateData(TRUE);
	m_StSpeedAx.EnableWindow(m_bActivateVRLocomotion&&m_bActivated);
	m_StSpeedAy.EnableWindow(m_bActivateVRLocomotion&&m_bActivated);
	m_StSpeedAz.EnableWindow(m_bActivateVRLocomotion&&m_bActivated);
	m_StSpeedRz.EnableWindow(m_bActivateVRLocomotion&&m_bActivated);
	m_EdSpeedAx.EnableWindow(m_bActivateVRLocomotion&&m_bActivated);
	m_EdSpeedAy.EnableWindow(m_bActivateVRLocomotion&&m_bActivated);
	m_EdSpeedAz.EnableWindow(m_bActivateVRLocomotion&&m_bActivated);
	m_EdSpeedRz.EnableWindow(m_bActivateVRLocomotion&&m_bActivated);
	m_BtReset.EnableWindow(m_bActivateVRLocomotion&&m_bActivated);

	m_SlSpeedAx.EnableWindow(m_bActivateVRLocomotion&&m_bActivated);
	m_SlSpeedAy.EnableWindow(m_bActivateVRLocomotion&&m_bActivated);
	m_SlSpeedAz.EnableWindow(m_bActivateVRLocomotion&&m_bActivated);
	m_SlSpeedRz.EnableWindow(m_bActivateVRLocomotion&&m_bActivated);

	m_BtSmoothMode.EnableWindow(m_bActivateVRLocomotion&&m_bActivated);

	OnBnClickedCkSmoothMode();
	m_SharedData.m_bActivateVRLocomotion = !!m_bActivateVRLocomotion;
	m_SharedMemory.Write((uint8_t*)&m_SharedData, sizeof(CSISharedData));
}

CString GetErrorString()
{
	TCHAR pMsg[1024];

	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),	MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPWSTR)&pMsg,1024,NULL);

	return CString(pMsg);
}

 CString GetWC(const char *c)
{
	const size_t cSize = strlen(c) + 1;
	wchar_t* wc = new wchar_t[cSize];
	mbstowcs(wc, c, cSize);
	CString sOut(wc);
	delete[]wc;
	return sOut;
}

void C3dRudderUnleashedVRConfig::InitOpenVR()
{
	vr::EVRInitError eVRInitError;
	vr::VR_Init(&eVRInitError, vr::VRApplication_Background);
	if (!vr::VRSystem() || eVRInitError != vr::VRInitError_None)
	{
		CString sErrorMessage;
		const char *pError = VR_GetVRInitErrorAsEnglishDescription(eVRInitError);
		CString sError = GetWC(pError);
		sErrorMessage.Format(_T("OpenVr Init Error : %s"), sError.GetBuffer());

		AfxMessageBox(sErrorMessage);
	}
}

void C3dRudderUnleashedVRConfig::CheckActivate()
{
	int nDriverSelected = m_CbDriver.GetCurSel();
	if (nDriverSelected != -1)
	{
		CString sDriverName;
		m_CbDriver.GetLBText(nDriverSelected, sDriverName);
		CString sPath = m_sSteamPath + _T("\\steamapps\\common\\SteamVR\\drivers\\") + sDriverName + _T("\\bin");
		CString sPathWin32 = sPath + _T("\\win32\\");
		CString sPathWin64 = sPath + _T("\\win64\\");
		CString sDriverChildPath64 = sPathWin64 + _T("ChildSteam.dll");

		FILE *pFile=_wfopen(sDriverChildPath64.GetBuffer(), L"rb");
		if (pFile)
		{
			m_bActivated = true;
			m_pSdk->HideSystemDevice(0, true);
			m_BtActivate.SetWindowText(_T("Deactivate"));

			InitOpenVR();

			UpdateData(FALSE);
			ManageActivateUI();
			fclose(pFile);
		}
	}
}

void OnWaitThread(void *_pDataTh)
{
	C3dRudderUnleashedVRConfig*pThis = (C3dRudderUnleashedVRConfig*)_pDataTh;

	CWaitDlg waitdlg(&pThis->m_bExitWait);
	waitdlg.DoModal();

	_endthread();
}

void C3dRudderUnleashedVRConfig::OnBnClickedBtActivate()
{
	int nDriverSelected = m_CbDriver.GetCurSel();
	if (nDriverSelected != -1)
	{
		m_bActivated ^= 1;

		if (m_bActivated)
		{
			m_BtActivate.SetWindowText(_T("Deactivate"));
			m_pSdk->HideSystemDevice(0, true);
		}
		else
		{
			vr::VR_Shutdown();
			m_BtActivate.SetWindowText(_T("Activate"));
			m_pSdk->HideSystemDevice(0, false);			
		}

		
		m_bExitWait = FALSE;
		_beginthread(OnWaitThread, 0, this);


		m_SharedMemory.Write((uint8_t*)&m_SharedData, sizeof(CSISharedData));

		CString sDriverName;
		m_CbDriver.GetLBText(nDriverSelected, sDriverName);
		CString sPath = m_sSteamPath + _T("\\steamapps\\common\\SteamVR\\drivers\\")+ sDriverName+_T("\\bin");
		
		DWORD nPID=FindProcessByName(_T("Steam.exe"));
		if (nPID != 0)
		{
			KillProcessTree(nPID);
			while (FindProcessByName(_T("Steam.exe")) != 0)
			{
				Sleep(100);
			}
		}

		nPID = FindProcessByName(_T("vrmonitor.exe"));
		if (nPID != 0)
			KillProcessTree(nPID);
		nPID = FindProcessByName(_T("vrserver.exe"));
		if (nPID != 0)
			KillProcessTree(nPID);
		nPID = FindProcessByName(_T("vrcompositor.exe"));
		if (nPID != 0)
			KillProcessTree(nPID);

		CString sPathWin32 = sPath + _T("\\win32\\");
		CString sPathWin64 = sPath + _T("\\win64\\");
		CString sDriverPath32_1 = sPathWin32 + _T("driver_") + sDriverName + _T(".dll");
		CString sDriverPath32_2 = sPathWin32 + _T("driver_") + sDriverName + _T("_copy.dll");
		CString sDriverPath64_1 = sPathWin64 + _T("driver_") + sDriverName + _T(".dll");
		CString sDriverPath64_2 = sPathWin64 + _T("driver_") + sDriverName + _T("_copy.dll");
		CString sDriverChildPath32 = sPathWin32 + _T("ChildSteam.dll");
		CString sDriverChildPath64 = sPathWin64 + _T("ChildSteam.dll");


		TCHAR buff[MAX_PATH];
		memset(buff, 0, MAX_PATH);
		::GetModuleFileName(NULL, buff, MAX_PATH);
		CString strFolder = buff;
		strFolder = strFolder.Left(strFolder.ReverseFind(_T('\\')) + 1);

		
		CString sDriverInjection32 = strFolder+_T("3dRudderUnleashedVRDriver32.dll");
		CString sDriverInjection64 = strFolder + _T("3dRudderUnleashedVRDriver64.dll");

		
		if (m_bActivated)
		{
			CString sError;
			CopyFile( sDriverPath32_1, sDriverPath32_2, TRUE);
			sError = GetErrorString();
			CopyFile( sDriverPath64_1, sDriverPath64_2, TRUE);
			sError = GetErrorString();
			CopyFile( sDriverPath32_1, sDriverChildPath32, TRUE);
			sError = GetErrorString();
			CopyFile( sDriverPath64_1, sDriverChildPath64, TRUE);
			sError = GetErrorString();

			CopyFile( sDriverInjection32, sDriverPath32_1, FALSE);
			sError = GetErrorString();
			CopyFile( sDriverInjection64, sDriverPath64_1, FALSE);
			sError = GetErrorString();
		}
		else
		{
			
			CopyFile( sDriverPath32_2, sDriverPath32_1, FALSE);
			CopyFile( sDriverPath64_2, sDriverPath64_1, FALSE);
			DeleteFile(sDriverChildPath32);
			DeleteFile(sDriverChildPath64);
		}
		

		CString sExePath = m_sSteamPath + _T("\\Steam.exe -applaunch 250820");
		RunProcess(sExePath.GetBuffer());
		
		if (m_bActivated)
		{
			//
			while (FindProcessByName(_T("vrserver.exe")) == 0)
			{
				Sleep(100);
			}
			InitOpenVR();
		}

		ManageActivateUI();
		m_bExitWait = TRUE;
	}
}




void C3dRudderUnleashedVRConfig::OnDestroy()
{
	CDialogEx::OnDestroy();

	if (m_bActivated)
		OnBnClickedBtActivate();

	ns3dRudder::EndSDK();	
}


void C3dRudderUnleashedVRConfig::OnBnClickedBtCalibration()
{	
	//SendMatrixHmd();
	CSI_MessageCalibration msgCalib;
	msgCalib.m_bCalib = true;
	g_SharedMessageHandleIn.PushMessage(&msgCalib);
}

void C3dRudderUnleashedVRConfig::OnBnClickedBtDebug()
{
	CRect rcButton;
	CRect rcGroupService;
	m_BtDebug.GetWindowRect(&rcButton);
	m_StDebug.GetWindowRect(&rcGroupService);
	CRect rcWin;
	GetWindowRect(&rcWin);
	ScreenToClient(&rcButton);
	ScreenToClient(&rcGroupService);
	m_bDebug ^= 1;
	if (m_bDebug)
	{
		SetWindowPos(NULL, 0, 0, rcWin.Width(), int(rcGroupService.bottom + 50.0f* m_fDPIx), SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
	}
	else
	{
		SetWindowPos(NULL, 0, 0, rcWin.Width(), int(rcButton.bottom + 40.0f* m_fDPIx),  SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
	}
}


void C3dRudderUnleashedVRConfig::OnEnChangeEdSpeedAx()
{
	UpdateData(TRUE);
	m_SharedData.m_fSpeed[0] = (float)_wtof(m_sSpeedAxisX);
	if (fabs(m_SharedData.m_fSpeed[0]) > m_MaxSpeedAx)
	{
		m_MaxSpeedAx = (int)fabs(m_SharedData.m_fSpeed[0]);
		m_SlSpeedAx.SetRange(-m_MaxSpeedAx * 100, m_MaxSpeedAx * 100);
		m_SlSpeedAx.SetTicFreq(m_MaxSpeedAx * 100 / 10);
	}
	m_SlSpeedAx.SetPos(int(m_SharedData.m_fSpeed[0] * 100));
}


void C3dRudderUnleashedVRConfig::OnEnChangeEdSpeedAy()
{
	UpdateData(TRUE);
	m_SharedData.m_fSpeed[1] = (float)_wtof(m_sSpeedAxisY);
	if (fabs(m_SharedData.m_fSpeed[1]) > m_MaxSpeedAy)
	{
		m_MaxSpeedAy = (int)fabs(m_SharedData.m_fSpeed[1]);
		m_SlSpeedAy.SetRange(-m_MaxSpeedAy * 100, m_MaxSpeedAy * 100);
		m_SlSpeedAy.SetTicFreq(m_MaxSpeedAy * 100 / 10);
	}
	m_SlSpeedAy.SetPos(int(m_SharedData.m_fSpeed[1] * 100));
}


void C3dRudderUnleashedVRConfig::OnEnChangeEdSpeedAz()
{
	UpdateData(TRUE);
	m_SharedData.m_fSpeed[2] = (float)_wtof(m_sSpeedAxisZ);
	if (fabs(m_SharedData.m_fSpeed[2]) > m_MaxSpeedAz)
	{
		m_MaxSpeedAz = (int)fabs(m_SharedData.m_fSpeed[2]);
		m_SlSpeedAz.SetRange(-m_MaxSpeedAz * 100, m_MaxSpeedAz * 100);
		m_SlSpeedAz.SetTicFreq(m_MaxSpeedAz * 100 / 10);
	}
	m_SlSpeedAz.SetPos(int(m_SharedData.m_fSpeed[2] * 100));
}


void C3dRudderUnleashedVRConfig::OnEnChangeEdSpeedRz()
{
	UpdateData(TRUE);
	m_SharedData.m_fSpeed[3] = (float)_wtof(m_sSpeedRotateZ);
	if (fabs(m_SharedData.m_fSpeed[3]) > m_MaxSpeedRz)
	{
		m_MaxSpeedRz = (int)fabs(m_SharedData.m_fSpeed[3]);
		m_SlSpeedRz.SetRange(-m_MaxSpeedRz * 100, m_MaxSpeedRz * 100);
		m_SlSpeedRz.SetTicFreq(m_MaxSpeedRz * 100 / 10);
	}
	m_SlSpeedRz.SetPos(int(m_SharedData.m_fSpeed[3] * 100));
}


void C3dRudderUnleashedVRConfig::OnEnChangeEdHeightOffset()
{
	UpdateData(TRUE);
	m_SharedData.m_fHeightOffset = (float)_wtof(m_sHeightOffset);
	if (fabs(m_SharedData.m_fHeightOffset) > m_nMaxHOffset)
	{
		m_nMaxHOffset = (int)fabs(m_SharedData.m_fHeightOffset);
		m_SlHOffset.SetRange(-m_nMaxHOffset * 100, m_nMaxHOffset * 100);
		m_SlHOffset.SetTicFreq(m_nMaxHOffset * 100 / 10);
	}
	m_SlHOffset.SetPos(int(m_SharedData.m_fHeightOffset * 100));
}


void C3dRudderUnleashedVRConfig::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	UpdateSliderValue();

	CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}

void C3dRudderUnleashedVRConfig::UpdateSliderValue()
{
	m_sSpeedAxisX.Format(_T("%.2f"), m_SlSpeedAx.GetPos() / 100.0f);
	m_sSpeedAxisY.Format(_T("%.2f"), m_SlSpeedAy.GetPos() / 100.0f);
	m_sSpeedAxisZ.Format(_T("%.2f"), m_SlSpeedAz.GetPos() / 100.0f);
	m_sSpeedRotateZ.Format(_T("%.2f"), m_SlSpeedRz.GetPos() / 100.0f);
	m_sHeightOffset.Format(_T("%.2f"), m_SlHOffset.GetPos() / 100.0f);

	m_sSmoothnessAx.Format(_T("%.3f"), m_SlSmoothnessAx.GetPos() / 1000.0f);
	m_sSmoothnessAy.Format(_T("%.3f"), m_SlSmoothnessAy.GetPos() / 1000.0f);
	m_sSmoothnessAz.Format(_T("%.3f"), m_SlSmoothnessAz.GetPos() / 1000.0f);
	m_sSmoothnessRz.Format(_T("%.3f"), m_SlSmoothnessRz.GetPos() / 1000.0f);


	UpdateData(FALSE);
}

void C3dRudderUnleashedVRConfig::OnBnClickedCkSmoothMode()
{
	UpdateData(TRUE);

	m_SlSmoothnessAx.EnableWindow(m_bActivated&&m_bActivateVRLocomotion&&m_bSmoothMode);
	m_SlSmoothnessAy.EnableWindow(m_bActivated&&m_bActivateVRLocomotion&&m_bSmoothMode);
	m_SlSmoothnessAz.EnableWindow(m_bActivated&&m_bActivateVRLocomotion&&m_bSmoothMode);
	m_SlSmoothnessRz.EnableWindow(m_bActivated&&m_bActivateVRLocomotion&&m_bSmoothMode);
	m_EdSmoothAx.EnableWindow(m_bActivated&&m_bActivateVRLocomotion&&m_bSmoothMode);
	m_EdSmoothAy.EnableWindow(m_bActivated&&m_bActivateVRLocomotion&&m_bSmoothMode);
	m_EdSmoothAz.EnableWindow(m_bActivated&&m_bActivateVRLocomotion&&m_bSmoothMode);
	m_EdSmoothRz.EnableWindow(m_bActivated&&m_bActivateVRLocomotion&&m_bSmoothMode);
	m_StSmotthAx.EnableWindow(m_bActivated&&m_bActivateVRLocomotion&&m_bSmoothMode);
	m_StSmotthAy.EnableWindow(m_bActivated&&m_bActivateVRLocomotion&&m_bSmoothMode);
	m_StSmotthAz.EnableWindow(m_bActivated&&m_bActivateVRLocomotion&&m_bSmoothMode);
	m_StSmotthRz.EnableWindow(m_bActivated&&m_bActivateVRLocomotion&&m_bSmoothMode);

}


void C3dRudderUnleashedVRConfig::OnEnChangeEdSmoothAx()
{
	UpdateData(TRUE);
	m_SharedData.m_fSmoothValue[0] = (float)_wtof(m_sSmoothnessAx);
	m_SlSmoothnessAx.SetPos(int(m_SharedData.m_fSmoothValue[0] * 1000));
}

void C3dRudderUnleashedVRConfig::OnEnChangeEdSmoothAy()
{
	UpdateData(TRUE);
	m_SharedData.m_fSmoothValue[1] = (float)_wtof(m_sSmoothnessAy);
	m_SlSmoothnessAy.SetPos(int(m_SharedData.m_fSmoothValue[1] * 1000));
}

void C3dRudderUnleashedVRConfig::OnEnChangeEdSmoothAz()
{
	UpdateData(TRUE);
	m_SharedData.m_fSmoothValue[2] = (float)_wtof(m_sSmoothnessAz);
	m_SlSmoothnessAz.SetPos(int(m_SharedData.m_fSmoothValue[2] * 1000));
}

void C3dRudderUnleashedVRConfig::OnEnChangeEdSmoothRz()
{
	UpdateData(TRUE);
	m_SharedData.m_fSmoothValue[3] = (float)_wtof(m_sSmoothnessRz);
	m_SlSmoothnessRz.SetPos(int(m_SharedData.m_fSmoothValue[3] * 1000));
}

